package com.example.server

import android.graphics.Bitmap
import android.os.Bundle
import android.os.Handler
import android.view.MotionEvent
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.SeekBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.channels.SelectionKey
import java.nio.channels.Selector
import java.nio.channels.SocketChannel
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.locks.ReentrantLock
import java.util.zip.Inflater

//config
var showSeekBar = true


//end of config

var showbtn = true

class imageInfo(
    var reso: Int = 0,
    var x: Int = 0,
    var y: Int = 0,
    var xlen: Int = 0,
    var ylen: Int = 0,
    var img: Bitmap? = null,
    var b: IntArray = IntArray(0)
)

var ip = "192.168.0.100"
var resize_width = 768
var resize_height = 768
var start_x = 200
var start_y = 0
var xlen = 500
var ylen = 768
var xlen_dst = 600
var ylen_dst = 700
var gap = 400
var isV = false
var lastShowTime = AtomicLong(System.currentTimeMillis())
var ctr_port = 58915


class checkThr : Thread() {
    override fun run() {
        while (true) {
            Thread.sleep(1000)
            if (System.currentTimeMillis() - lastShowTime.get() > 1000 * 60 * 30) {
                System.exit(0)
            }
        }
    }
}

lateinit var ss1: ByteBuffer
lateinit var ss: ByteBuffer
var ss_co: Long = 0
lateinit var ori_img: Bitmap
var ori_co: Long = 0
lateinit var dst_img: Bitmap
var dst_co: Long = 0

var lock = ReentrantLock()
var toStop = false
var toStop2 = true
var dst_thr_stop_sign = false
var ori_thr_stop_sign = false

class dst_thr : Thread() {
    lateinit var upper: MainActivity
    override fun run() {
        while (true) {
            try {
                work()
            } catch (e: Exception) {
                e.printStackTrace()
                continue
            }
        }
    }

    fun work() {
        if (xlen_dst % xlen == 0 && ylen_dst % ylen == 0 && xlen_dst / xlen == ylen_dst / ylen) {
            dst_thr_stop_sign = false
            Thread.sleep(50)
            return
        }
        if (dst_co == ori_co) {
            dst_thr_stop_sign = false
            Thread.sleep(50)
            return
        }
        lock.lock()
        val resized = Bitmap.createScaledBitmap(ori_img, xlen_dst, ylen_dst, false)
        lock.unlock()

        var imageSize = xlen_dst * ylen_dst * 4
        val uncompressedBuffer = ByteBuffer.allocateDirect(imageSize)
        resized.copyPixelsToBuffer(uncompressedBuffer)
        uncompressedBuffer.position(0)
        var aa = uncompressedBuffer.array()
        var br2 = ByteArray(xlen_dst * ylen_dst * 4)
        for (j in 0 until +ylen_dst) {
            for (i in 0 until xlen_dst) {
                var startPos = i + j * xlen_dst
                var x = aa[startPos * 4].toUByte().toInt() + aa[startPos * 4 + 1].toUByte()
                    .toInt() + aa[startPos * 4 + 2].toUByte().toInt()
                if (x > gap) {
                    br2[startPos * 4] = -1
                    br2[startPos * 4 + 1] = -1
                    br2[startPos * 4 + 2] = -1
                    br2[startPos * 4 + 3] = -1
                } else {
                    br2[startPos * 4] = 0
                    br2[startPos * 4 + 1] = 0
                    br2[startPos * 4 + 2] = 0
                    br2[startPos * 4 + 3] = -1
                }
            }
        }
        dst_co++;
        if (dst_co < ori_co) {
            dst_co = ori_co - 1
        }
        var b2 = ByteBuffer.wrap(br2)
        dst_img = Bitmap.createBitmap(xlen_dst, ylen_dst, Bitmap.Config.ARGB_8888)
        dst_img.copyPixelsFromBuffer(b2)
        upper.runOnUiThread({ upper.show(dst_img) })
    }
}


class ori_thr : Thread() {
    lateinit var upper: MainActivity
    override fun run() {
        while (true) {
            try {
                work()
            } catch (e: Exception) {
                e.printStackTrace()
                continue
            }
        }
    }

    fun work() {
        if (ori_co == ss_co) {
            if (ori_thr_stop_sign) {
                ori_thr_stop_sign = false
            }

            Thread.sleep(50)
            return
        }
        var bigger = 1
        if (xlen_dst % xlen == 0 && ylen_dst % ylen == 0 && xlen_dst / xlen == ylen_dst / ylen) {
            bigger = xlen_dst / xlen
        }

        var br = ByteArray(xlen * bigger * ylen * bigger * 4)
        var hasFreshTime = false
        lock.lock()
        ss = ss1
        lock.unlock()
        if (!isV) {
            for (j in 0 until ylen) {
                for (i in 0 until xlen) {
                    var rr = ss.get()

                    if (rr == 0.toByte()) {
                        for (ii in i * bigger until (i + 1) * bigger) {
                            for (jj in j * bigger until (j + 1) * bigger) {
                                var va = (ii + xlen * bigger * jj) * 4
                                br[va] = 0
                                br[va + 1] = 0
                                br[va + 2] = 0
                                br[va + 3] = -1
                            }
                        }
                    } else {
                        if (!hasFreshTime) {
                            hasFreshTime = true
                            lastShowTime.set(System.currentTimeMillis())
                        }
                        for (ii in i * bigger until (i + 1) * bigger) {
                            for (jj in j * bigger until (j + 1) * bigger) {
                                var va = (ii + xlen * bigger * jj) * 4
                                br[va] = -1
                                br[va + 1] = -1
                                br[va + 2] = -1
                                br[va + 3] = -1
                            }
                        }
                    }
                }
            }
        } else {
            for (i in 0 until xlen) {
                for (j in 0 until ylen) {
                    var rr = ss.get()
                    if (rr == 0.toByte()) {
                        for (ii in i * bigger until (i + 1) * bigger) {
                            for (jj in (ylen - j - 1) * bigger until (ylen - j) * bigger) {
                                var va = (ii + xlen * bigger * jj) * 4
                                br[va] = 0
                                br[va + 1] = 0
                                br[va + 2] = 0
                                br[va + 3] = -1
                            }
                        }
                    } else {
                        if (!hasFreshTime) {
                            hasFreshTime = true
                            lastShowTime.set(System.currentTimeMillis())
                        }
                        for (ii in i * bigger until (i + 1) * bigger) {
                            for (jj in (ylen - j - 1) * bigger until (ylen - j) * bigger) {
                                var va = (ii + xlen * bigger * jj) * 4
                                br[va] = -1
                                br[va + 1] = -1
                                br[va + 2] = -1
                                br[va + 3] = -1
                            }
                        }

                    }
                }
            }
        }
        var b = ByteBuffer.wrap(br)
        lock.lock()
        ori_img = Bitmap.createBitmap(xlen * bigger, ylen * bigger, Bitmap.Config.ARGB_8888)
        ori_img.copyPixelsFromBuffer(b)
        ori_co++;
        if (ori_co < ss_co) {
            ori_co = ss_co - 1
        }

        lock.unlock()
        if (xlen_dst % xlen == 0 && ylen_dst % ylen == 0 && xlen_dst / xlen == ylen_dst / ylen) {
            upper.runOnUiThread({ upper.show(ori_img) })
        }
    }
}


class thrC : Thread() {
    lateinit var upper: MainActivity
    var maxWaitTime_default = 5 * 1000.toLong()
    var maxWaitTime = 5 * 1000.toLong()
    override fun run() {
        while (true) {
            maxWaitTime = maxWaitTime_default
            if (toStop) {
                dst_thr_stop_sign = true
                ori_thr_stop_sign = true
                while (dst_thr_stop_sign || ori_thr_stop_sign) {
                    Thread.sleep(10)
                }
                toStop = false
                toStop2 = true
                upper.runOnUiThread({ upper.setT() })
            }
            if (toStop2) {
                Thread.sleep(100)
                continue
            }
            var xx = w()
            if (xx.array().size == 0) continue
            lock.lock()
            ss1 = xx
            ss_co++;
            lock.unlock()
        }
    }

    fun w(): ByteBuffer {
        var s: SocketChannel? = null
        try {
            s = SocketChannel.open()
        } catch (e: Exception) {
            e.printStackTrace()
            return ByteBuffer.allocate(0)
        }

        try {
            var add = InetSocketAddress(ip, 8999)
            var sT = System.currentTimeMillis()

            s.connect(add)
            var b = ByteBuffer.allocate(7 * 4)
            b.order(ByteOrder.LITTLE_ENDIAN)
            if (!isV) {
                b.putInt(resize_width)
                b.putInt(resize_height)
                b.putInt(start_x)
                b.putInt(start_y)
                b.putInt(xlen)
                b.putInt(ylen)
                b.putInt(gap)
            } else {
                b.putInt(resize_height)
                b.putInt(resize_width)
                b.putInt(start_y)
                b.putInt(start_x)
                b.putInt(ylen)
                b.putInt(xlen)
                b.putInt(gap)
            }
            b.flip()
            s.write(b)

            var info = ByteBuffer.allocate(1)
            s.read(info)
            info.flip()
            var ty = info.get()
            var len = xlen * ylen

            if (ty == 1.toByte()) {
                info = ByteBuffer.allocate(4)
                info.order(ByteOrder.BIG_ENDIAN)
                s.read(info)
                info.flip()
                len = info.getInt()
            }


            s.configureBlocking(false)
            var se = Selector.open()
            s.register(se, SelectionKey.OP_READ)

            var ss = ByteBuffer.allocate(len)
            var re = 0
            while (re != len) {
                if (System.currentTimeMillis() - sT > maxWaitTime) {
                    println("return 2")
                    s.close()
                    se.close()
                    return ByteBuffer.allocate(0)
                }
                var r = se.select(maxWaitTime + 100 - (System.currentTimeMillis() - sT))
                if (System.currentTimeMillis() - sT > maxWaitTime) {
                    println("return 1")
                    s.close()
                    se.close()
                    return ByteBuffer.allocate(0)
                }


                var x = s.read(ss)
                if (x <= 0 && re != len) {
                    println("return 0 ${x},${re}")
                    s.close()
                    return ByteBuffer.allocate(0)
                }
                re += x
            }
            se.close()
            s.close()
            ss.flip()
            if (ty == 0.toByte()) return ss
            var f = Inflater()
            f.setInput(ss.array())
            var bb = ByteArray(xlen * ylen)
            var ii = f.inflate(bb)
            if (!f.finished() || ii != xlen * ylen) return ByteBuffer.allocate(0)
            return ByteBuffer.wrap(bb)
        } catch (e: Exception) {
            e.printStackTrace()
            s.close()
            return ByteBuffer.allocate(0)
        }
    }
}

var forceRet = false

class ctr_thr : Thread() {
    lateinit var upper: MainActivity
    var maxWaitTime_default = 5 * 1000.toLong()
    var maxWaitTime = 5 * 1000.toLong()
    override fun run() {
        while (true) {
            if (forceRet) {
                forceRet = false
                w()
            } else {
                Thread.sleep(10)
            }
        }
    }

    fun w() {
        var s: SocketChannel? = null
        try {
            s = SocketChannel.open()
        } catch (e: Exception) {
            e.printStackTrace()
            return
        }

        try {
            var add = InetSocketAddress(ip, ctr_port)
            s.connect(add)
            s.close()
        } catch (e: Exception) {
            e.printStackTrace()
            s.close()
        }
    }
}


class RepeatListener(
    initialInterval: Int, normalInterval: Int,
    clickListener: View.OnClickListener?
) : View.OnTouchListener {
    private val handler: Handler = Handler()
    private val initialInterval: Int
    private val normalInterval: Int
    private val clickListener: View.OnClickListener
    private var touchedView: View? = null
    private val handlerRunnable: Runnable = object : Runnable {
        override fun run() {
            if (touchedView?.isEnabled()!!) {
                handler.postDelayed(this, normalInterval.toLong())
                if (clickListener != null) {
                    clickListener.onClick(touchedView)
                }
            } else {
                handler.removeCallbacks(this)
                touchedView!!.setPressed(false)
                touchedView = null
            }
        }
    }

    override fun onTouch(view: View?, motionEvent: MotionEvent): Boolean {
        when (motionEvent.action) {
            MotionEvent.ACTION_DOWN -> {
                handler.removeCallbacks(handlerRunnable)
                handler.postDelayed(handlerRunnable, initialInterval.toLong())
                touchedView = view
                touchedView?.setPressed(true)
                clickListener.onClick(view)
                return true
            }

            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                handler.removeCallbacks(handlerRunnable)
                touchedView?.setPressed(false)
                touchedView = null
                return true
            }
        }
        return false
    }

    init {
        requireNotNull(clickListener) { "null runnable" }
        require(!(initialInterval < 0 || normalInterval < 0)) { "negative interval" }
        this.initialInterval = initialInterval
        this.normalInterval = normalInterval
        this.clickListener = clickListener
    }
}

var sel_num = 0

class MainActivity : AppCompatActivity() {
    var hasStart = false
    var stepMode = false
    var picTouchTime = System.currentTimeMillis()
    var im = imageInfo()
    var lastKeyDown = System.currentTimeMillis() - 100000
    var keyDownCause = 0 //0:to 0,1:pause
    var lastText = ""
    var t = thrC()
    var seekbar_fake = false
    fun saveText() {
        var name = sel_num.toString()
        var path: File = baseContext.filesDir
        var file: File = File(path, name)
        var f = FileOutputStream(file)
        var bb = ByteBuffer.allocate(100)
        var b = findViewById<EditText>(R.id.ip).text.toString().toByteArray()
        bb.putInt(b.size)
        bb.put(b)
        f.write(bb.array())
        f.close()
    }

    fun iniText() {
        var name = sel_num.toString()
        var path: File = baseContext.filesDir
        var file: File = File(path, name)
        val f = FileInputStream(file)
        val b = ByteArray(100)
        f.read(b, 0, 100)
        f.close()
        var bb = ByteBuffer.wrap(b)
        var l = bb.getInt()
        var stb = ByteArray(l)
        bb.get(stb)
        var st = String(stb)
        findViewById<EditText>(R.id.ip).setText(st)
    }

    fun setT() {
        saveText()
        var b = findViewById<EditText>(R.id.ip).text.toString()
        if (b == lastText) {
            isV = !isV
        }
        if (isV) {
            findViewById<Button>(R.id.button).setText("v")
        } else {
            findViewById<Button>(R.id.button).setText("h")
        }

        lastText = b
        var ll = b.split("-")
        var resize = ll[0].split(".")
        var geo = ll[1].split(".")
        var resize_dst = ll[2].split(".")
        gap = ll[3].toInt()
        ip = ll[4]

        resize_width = resize[0].toInt()
        resize_height = resize[1].toInt()
        if (resize_height == 0) {
            resize_height = resize_width
        }

        start_x = geo[0].toInt()
        start_y = geo[1].toInt()
        xlen = geo[2].toInt()
        if (xlen + start_x > resize_width) {
            xlen = resize_width - start_x
        }
        ylen = geo[3].toInt()
        if (ylen + start_y > resize_height) {
            ylen = resize_height - start_y
        }
        if (resize_dst[0].contains("+")) {
            xlen_dst = resize_dst[0].replace("+", "").toInt() * xlen
        } else {
            xlen_dst = resize_dst[0].toInt()
        }
        if (resize_dst[1].contains("+")) {
            ylen_dst = resize_dst[1].replace("+", "").toInt() * ylen
        } else {
            ylen_dst = resize_dst[1].toInt()
        }
        toStop2 = false
        iniSeekBar()
        t.maxWaitTime = 1000
        forceRet = true
    }

    fun iniSeekBar() {
        var a = findViewById<Button>(R.id.seekBar1b0).text.toString().toInt()
        if (a == 1) {
            if (findViewById<SeekBar>(R.id.seekBar1).max != resize_width - xlen)
                seekbar_fake = true
            findViewById<SeekBar>(R.id.seekBar1).max = resize_width - xlen
            findViewById<SeekBar>(R.id.seekBar1).progress = start_x
        }

        if (a == 2) {
            if (findViewById<SeekBar>(R.id.seekBar1).max != resize_height - ylen)
                seekbar_fake = true
            findViewById<SeekBar>(R.id.seekBar1).max = resize_height - ylen
            findViewById<SeekBar>(R.id.seekBar1).progress = start_y
        }
        if (a == 3) {
            if (findViewById<SeekBar>(R.id.seekBar1).max != 255 * 3)
                seekbar_fake = true
            findViewById<SeekBar>(R.id.seekBar1).max = 255 * 3
            findViewById<SeekBar>(R.id.seekBar1).progress = gap
        }
    }

    fun hidebar(invert: Boolean) {
        if (invert) {
            showSeekBar = !showSeekBar
        }
        if (!showSeekBar) {
            findViewById<Button>(R.id.sel_btn).visibility = View.GONE
            findViewById<Button>(R.id.seekBar1b0).visibility = View.GONE
            findViewById<Button>(R.id.seekBar1b1).visibility = View.GONE
            findViewById<Button>(R.id.seekBar1b2).visibility = View.GONE
            findViewById<SeekBar>(R.id.seekBar1).visibility = View.GONE
            findViewById<TextView>(R.id.seekBar1t).visibility = View.GONE
        } else {
            findViewById<Button>(R.id.sel_btn).visibility = View.VISIBLE
            findViewById<Button>(R.id.seekBar1b0).visibility = View.VISIBLE
            findViewById<Button>(R.id.seekBar1b1).visibility = View.VISIBLE
            findViewById<Button>(R.id.seekBar1b2).visibility = View.VISIBLE
            findViewById<SeekBar>(R.id.seekBar1).visibility = View.VISIBLE
            findViewById<TextView>(R.id.seekBar1t).visibility = View.VISIBLE
        }
    }

    fun hidebar2(invert: Boolean) {
        if (invert) {
            showbtn = !showbtn
        }
        if (!showbtn) {
            findViewById<Button>(R.id.button).visibility = View.GONE
            findViewById<Button>(R.id.quit_btn).visibility = View.GONE
            findViewById<EditText>(R.id.ip).visibility = View.GONE

        } else {
            findViewById<Button>(R.id.button).visibility = View.VISIBLE
            findViewById<Button>(R.id.quit_btn).visibility = View.VISIBLE
            findViewById<EditText>(R.id.ip).visibility = View.VISIBLE

        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        this.getSupportActionBar()?.hide();
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        hasStart = true
        try {
            iniText()
        } catch (e: Exception) {
        }
        var xx = checkThr()
        xx.isDaemon = true
        xx.start()
        var ctrT = ctr_thr()
        ctrT.isDaemon = true
        ctrT.start()
        findViewById<Button>(R.id.sel_btn).setOnClickListener {
            sel_num = findViewById<SeekBar>(R.id.seekBar1).progress
            findViewById<Button>(R.id.sel_btn).text = sel_num.toString()
            try {
                iniText()
            } catch (e: Exception) {
            }
        }

        findViewById<Button>(R.id.quit_btn).setOnClickListener {
            System.exit(0)
        }

        var inte = 30
        findViewById<Button>(R.id.seekBar1b0).setOnClickListener {
            var a = findViewById<Button>(R.id.seekBar1b0).text.toString().toInt()
            if (a == 3) {
                a = 0
            }
            findViewById<Button>(R.id.seekBar1b0).setText((a + 1).toString())
            iniSeekBar()
        }
        if (!showSeekBar) {
            hidebar(false)
        }
        findViewById<Button>(R.id.seekBar1b0).setOnLongClickListener {
            hidebar(true)
            true
        }

        findViewById<SeekBar>(R.id.seekBar1).setOnSeekBarChangeListener(object :
            SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(
                seekBar: SeekBar,
                progress: Int,
                fromUser: Boolean
            ) {
                if (seekbar_fake) {
                    seekbar_fake = false
                } else {
                    findViewById<TextView>(R.id.seekBar1t).setText(progress.toString())
                    var a = findViewById<Button>(R.id.seekBar1b0).text.toString().toInt()
                    if (a == 1) {
                        start_x = progress
                    }
                    if (a == 2) {
                        start_y = progress
                    }
                    if (a == 3) {
                        gap = progress
                    }
                    t.maxWaitTime = 1000
                    forceRet = true
                }
            }

            override fun onStartTrackingTouch(seekBar: SeekBar) {}
            override fun onStopTrackingTouch(seekBar: SeekBar) {}
        })

        findViewById<Button>(R.id.seekBar1b1).setOnTouchListener(
            RepeatListener(400, inte,
                object : View.OnClickListener {
                    override fun onClick(view: View?) {
                        findViewById<SeekBar>(R.id.seekBar1).setProgress(findViewById<SeekBar>(R.id.seekBar1).progress - 1)
                    }
                })
        )

        findViewById<Button>(R.id.seekBar1b2).setOnTouchListener(
            RepeatListener(400, inte,
                object : View.OnClickListener {
                    override fun onClick(view: View?) {
                        findViewById<SeekBar>(R.id.seekBar1).setProgress(findViewById<SeekBar>(R.id.seekBar1).progress + 1)
                    }
                })
        )

        findViewById<Button>(R.id.button).setOnLongClickListener {
            hidebar(true)
            true
        }

        t.isDaemon = true
        t.upper = this
        t.start()
        var t2 = ori_thr()
        t2.isDaemon = true
        t2.upper = this
        t2.start()
        var t3 = dst_thr()
        t3.isDaemon = true
        t3.upper = this
        t3.start()

        findViewById<Button>(R.id.sel_btn).setOnLongClickListener() {
            System.exit(0)
            true
        }
        findViewById<Button>(R.id.button).setOnClickListener() {
            toStop = true
        }
        findViewById<ImageView>(R.id.imageView).setOnClickListener() {
            if (System.currentTimeMillis() - picTouchTime < 200)
                hidebar2(true)
            picTouchTime = System.currentTimeMillis()

        }
    }

    fun show(ret: Bitmap) {
        findViewById<ImageView>(R.id.imageView).setImageBitmap(ret)
        return
    }
}

